import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.util.FileUtils;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class JGitSparseCloneExample {

    private static final String REMOTE_URL = "https://github.com/eclipse-jgit/jgit.git"; // 替换为您的 Git 仓库 URL
    private static final String LOCAL_PATH = "d:/code/yiqun/jgit-sparse-clone-repo"; // 本地克隆路径

    public static void main(String[] args) {
        File localRepoDir = new File(LOCAL_PATH);

        try {
            // 1. 清理之前的克隆（如果存在）
            if (localRepoDir.exists()) {
                System.out.println("Cleaning up existing repository at: " + LOCAL_PATH);
                FileUtils.delete(localRepoDir, FileUtils.RECURSIVE);
            }

            // 2. 执行稀疏克隆
            System.out.println("Cloning repository (sparse checkout enabled) from " + REMOTE_URL + " to " + LOCAL_PATH);

            // 定义要稀疏检出的路径
            List<String> sparseCheckoutPaths = Arrays.asList(
                "org.eclipse.jgit/src/org/eclipse/jgit/api",
                "org.eclipse.jgit.test/tst/org/eclipse/jgit/api"
            );

            Git git = Git.cloneRepository()
                    .setURI(REMOTE_URL)
                    .setDirectory(localRepoDir)
                    .setNoCheckout(true) // 先不检出任何文件
                    .call();

            Repository repository = git.getRepository();

            // 启用稀疏检出
            repository.getConfig().setBoolean("core", null, "sparseCheckout", true);
            repository.getConfig().save();

            // 写入 .git/info/sparse-checkout 文件
            Path sparseCheckoutFile = Paths.get(localRepoDir.getAbsolutePath(), ".git", "info", "sparse-checkout");
            Files.write(sparseCheckoutFile, sparseCheckoutPaths);

            // 执行检出操作，这将根据 sparse-checkout 文件检出文件
            git.checkout()
                    .addPaths(sparseCheckoutPaths) // 添加要检出的路径
                    .call();

            System.out.println("Sparse clone completed successfully.");

            // 3. 验证结果
            System.out.println("\nVerifying cloned files:");
            Set<String> actualFiles = Files.walk(localRepoDir.toPath())
                    .filter(Files::isRegularFile)
                    .map(p -> localRepoDir.toPath().relativize(p).toString().replace("\\", "/")) // 统一路径分隔符
                    .collect(Collectors.toSet());

            System.out.println("Cloned files:");
            actualFiles.forEach(System.out::println);

            // 检查是否包含预期的稀疏检出路径中的文件
            boolean allExpectedPathsPresent = true;
            for (String path : sparseCheckoutPaths) {
                if (!actualFiles.stream().anyMatch(f -> f.startsWith(path))) {
                    System.err.println("Error: Expected path '" + path + "' not found in cloned repository.");
                    allExpectedPathsPresent = false;
                }
            }
            if (allExpectedPathsPresent) {
                System.out.println("All specified sparse checkout paths appear to be present.");
            }

        } catch (GitAPIException | IOException e) {
            System.err.println("Error during sparse clone: " + e.getMessage());
            e.printStackTrace();
        } finally {
            // 4. 清理（可选）
            // try {
            //     if (localRepoDir.exists()) {
            //         System.out.println("\nCleaning up cloned repository at: " + LOCAL_PATH);
            //         FileUtils.delete(localRepoDir, FileUtils.RECURSIVE);
            //     }
            // } catch (IOException e) {
            //     System.err.println("Error cleaning up repository: " + e.getMessage());
            //     e.printStackTrace();
            // }
        }
    }
}